package com.ruoyi.cost.controller;

import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.cost.domain.FileEntity;
import com.ruoyi.cost.domain.NameField;
import com.ruoyi.cost.service.INameFieldService;
import com.ruoyi.cost.service.impl.NameFieldServiceImpl;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

@RestController
@RequestMapping("xmltojson")
public class CostController extends BaseController {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private INameFieldService nameFieldService;
    private String modeName;
    private String modeYear;
    private String modeRule;
    private String modeId;

    @PostMapping("/uploadExcel")
    public AjaxResult uploadExcel(@RequestParam("file") MultipartFile file) throws IOException {
        Map<String, List<Map<String, Object>>> excelData = new HashMap<>();

// 将 MultipartFile 转换为临时物理文件
        File tempFile = File.createTempFile("uploaded", ".zip");
        file.transferTo(tempFile);
        Long userId = SecurityUtils.getUserId();
// 使用指定编码创建 ZipFile 对象
        try (ZipFile zipFile = new ZipFile(tempFile, Charset.forName("GBK"))) {
            Enumeration<? extends ZipEntry> entries = zipFile.entries();

            while (entries.hasMoreElements()) {
                ZipEntry zipEntry = entries.nextElement();

                // 只处理 Excel 文件
                if (!zipEntry.isDirectory() && (zipEntry.getName().endsWith(".xlsx") || zipEntry.getName().endsWith(".xls"))) {
                    try (InputStream stream = zipFile.getInputStream(zipEntry)) {
                        // 去除文件后缀，作为Map的key
                        String fileNameWithoutExtension = zipEntry.getName().replaceFirst("\\.xlsx?$", "");

                        List<Map<String, Object>> sheetData = processExcel(stream);

                        // 存入Map，去掉后缀的文件名作为key
                        excelData.put(fileNameWithoutExtension, sheetData);
                    } catch (Exception e) {
                        System.err.println("Error processing Excel file: " + zipEntry.getName() + " - " + e.getMessage());
                    }
                }
            }
        } finally {
            // 删除临时文件
            tempFile.delete();
        }
        excelData.forEach((key, value) -> {
            if (value.size() != 0) {
                redisTemplate.opsForList().rightPushAll(userId + ":" + key, (List<?>) value);
            }
        });
        return success(excelData);
    }

    // 处理单个 Excel 文件
    private List<Map<String, Object>> processExcel(InputStream excelStream) throws IOException {
        List<Map<String, Object>> sheetData = new ArrayList<>();

        try (Workbook workbook = new XSSFWorkbook(excelStream)) {
            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                Sheet sheet = workbook.getSheetAt(i);
                if (sheet != null) {
                    processSheet(sheet, sheetData);
                }
            }
        }

        return sheetData;
    }

    // 解析一个 sheet
    private void processSheet(Sheet sheet, List<Map<String, Object>> sheetData) {
        Row headerRow = sheet.getRow(0);
        if (headerRow == null) {
            return;
        }

        int numColumns = headerRow.getPhysicalNumberOfCells();

        for (int rowIdx = 1; rowIdx <= sheet.getLastRowNum(); rowIdx++) {
            Row row = sheet.getRow(rowIdx);
            Map<String, Object> rowData = new HashMap<>();

            for (int colIdx = 0; colIdx < numColumns; colIdx++) {
                Cell cell = row.getCell(colIdx);
                String columnName = headerRow.getCell(colIdx).getStringCellValue();
                Object cellValue = getCellValue(cell);
                rowData.put(columnName, cellValue);
            }

            sheetData.add(rowData);
        }
    }

    // 获取单元格内容
    private Object getCellValue(Cell cell) {
        if (cell == null) {
            return null;
        }

        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue();
                } else {
                    return cell.getNumericCellValue();
                }
            case BOOLEAN:
                return cell.getBooleanCellValue();
            case FORMULA:
                return cell.getCellFormula();
            default:
                return null;
        }
    }

    @PostMapping("/download")
    public ResponseEntity<byte[]> downloadFile() {
        try {
            // 从数据库中获取所有文件
            List<FileEntity> files = nameFieldService.getFileById();

            if (files == null || files.isEmpty()) {
                throw new RuntimeException("没有可下载的文件！");
            }

            // 创建 ZIP 文件流
            try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                 ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream)) {

                for (FileEntity file : files) {
                    if (file.getFileData() == null || file.getFileData().length == 0) {
                        System.out.println("文件数据为空: " + file.getFileName());
                        continue;
                    }

                    // 写入 ZIP 条目
                    ZipEntry zipEntry = new ZipEntry(file.getFileName());
                    zipOutputStream.putNextEntry(zipEntry);
                    zipOutputStream.write(file.getFileData());
                    zipOutputStream.closeEntry();
                }

                zipOutputStream.finish(); // 确保 ZIP 完成写入

                byte[] zipBytes = byteArrayOutputStream.toByteArray();
                System.out.println("生成的 ZIP 文件大小: " + zipBytes.length); // 打印 ZIP 文件大小

                // 返回 ZIP 文件作为响应
                return ResponseEntity.ok()
                        .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=all_files.zip")
                        .contentType(MediaType.APPLICATION_OCTET_STREAM)
                        .body(zipBytes);

            }
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }

    @PostMapping("/upload")
    public AjaxResult uploadXmlFile(@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            return AjaxResult.error("上传失败，文件为空！");
        }

        try {
            // 保存文件到数据库
            nameFieldService.saveFile(file);
        } catch (Exception e) {
        }

        try {
            Long userId = SecurityUtils.getUserId();

            Map<String, Object> map = new HashMap<>();

            // 使用系统默认的临时目录
            File tempDir = Files.createTempDirectory("temp").toFile();
            tempDir.deleteOnExit(); // 确保在程序结束时删除临时目录

            // 解压主ZIP文件到临时目录
            try (ZipInputStream zis = new ZipInputStream(file.getInputStream())) {
                ZipEntry outerEntry;
                while ((outerEntry = zis.getNextEntry()) != null) {
                    if (outerEntry.getName().endsWith(".zip")) {
                        File innerZipFile = new File(tempDir, sanitizeFileName(outerEntry.getName()));
                        innerZipFile.getParentFile().mkdirs(); // 确保父目录存在

                        try (FileOutputStream fos = new FileOutputStream(innerZipFile)) {
                            byte[] buffer = new byte[1024];
                            int len;
                            while ((len = zis.read(buffer)) > 0) {
                                fos.write(buffer, 0, len);
                            }
                        }
                        // 处理内层ZIP文件
                        processInnerZip(innerZipFile, map, userId);
                    }
                }
            }

            // 删除临时目录及文件
            deleteDirectory(tempDir);

            return success(map);

        } catch (ParserConfigurationException | SAXException | IOException e) {
            e.printStackTrace();
            return error();
        }
    }

    private String sanitizeFileName(String fileName) {
        // 替换路径中的特殊字符
        return fileName.replaceAll("[<>:\"/\\|?*]", "_");
    }

    private void processInnerZip(File zipFile, Map<String, Object> map, Long userId) throws IOException, ParserConfigurationException, SAXException {
        try (ZipFile zip = new ZipFile(zipFile)) {
            Enumeration<? extends ZipEntry> entries = zip.entries();
            while (entries.hasMoreElements()) {
                ZipEntry entry = entries.nextElement();
                if (entry.isDirectory()) {
                    // 处理目录中的文件
                    processDirectory(zip, entry, map, userId);
                } else if (entry.getName().endsWith(".xml")) {
                    processXmlEntry(zip, entry, map, userId);
                }
            }
        }
    }

    private void processXmlEntry(ZipFile zip, ZipEntry entry, Map<String, Object> map, Long userId) throws IOException, ParserConfigurationException, SAXException {
        try (InputStream stream = zip.getInputStream(entry)) {
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(stream);
            doc.getDocumentElement().normalize();

            JSONObject json = convertToJSON(doc.getDocumentElement());
            Map<String, Object> extractedData = jsonToMap(json);
            Map map1 = toMap(extractedData.get("电子账簿")) ;
            if (map1 != null && map1.size()>0){
                modeYear = (String) map1.get("会计年度");
            }
            Map map2 = toMap(extractedData.get("电子账簿")) ;
            if (map2 != null && map2.size()>0){
                modeName = (String) map2.get("会计年度");
            }
            Map map3 = toMap(extractedData.get("总账基础信息")) ;
            if (map3 != null && map3.size()>0){
                modeYear = (String) map3.get("会计科目编号规则");
            }
            extractedData.forEach((key, value) -> {
                redisTemplate.opsForList().rightPushAll(userId + ":" + key, (List<?>) value);
                map.put(key, value);
            });
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public static Map<String, Object> toMap(Object obj) throws IllegalAccessException {
        Map<String, Object> map = new HashMap<>();

        if (obj != null) {
            Class<?> clazz = obj.getClass();
            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true); // 使得私有字段也可以访问
                map.put(field.getName(), field.get(obj));
            }
        }

        return map;
    }

    private void processDirectory(ZipFile zip, ZipEntry dir, Map<String, Object> map, Long userId) throws IOException, ParserConfigurationException, SAXException {
        Enumeration<? extends ZipEntry> entries = zip.entries();
        while (entries.hasMoreElements()) {
            ZipEntry entry = entries.nextElement();
            if (entry.getName().startsWith(dir.getName()) && !entry.getName().equals(dir.getName())) {
                // 处理子目录中的文件
                if (entry.getName().endsWith(".xml")) {
                    processXmlEntry(zip, entry, map, userId);
                }
            }
        }
    }


    private void deleteDirectory(File directory) {
        File[] files = directory.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    deleteDirectory(file);
                } else {
                    file.delete();
                }
            }
        }
        directory.delete();
    }

    @GetMapping("/data")
    public AjaxResult getData(
            @RequestParam String key,
            @RequestParam int page,
            @RequestParam int size
            ) {
        Long userId = SecurityUtils.getUserId();

        String redisKey = userId + ":" + key;
        Long total = redisTemplate.opsForList().size(redisKey);
        if (total == null || total == 0) {
            return error();
        }
        int start = page * size;
        int end = Math.min(start + size - 1, total.intValue() - 1);

        List<JSONObject> pageData = redisTemplate.opsForList().range(redisKey, start, end);
        Map<String, Object> response = new HashMap<>();

        response.put("data", pageData);
        response.put("total", total);
        return success(response);
    }

    @PostMapping("/save")
    public AjaxResult saveData( ) {
        try {
            Long userId = SecurityUtils.getUserId();
            String s1 = UUID.randomUUID().toString();

            // 获取所有以 userId 为前缀的键
            Set<String> keys = redisTemplate.keys(userId + ":*");
            Map<String, List<HashMap<String, String>>> allData = new HashMap<>();
            if (keys != null) {
                for (String key : keys) {
                    List<HashMap<String, String>> dataList = redisTemplate.opsForList().range(key, 0, -1);
                    if (dataList != null) {
                        allData.put(key.replace(userId + ":", ""), dataList);
                    }
                }
            }
            List<HashMap<String,String>> tableNameTem = nameFieldService.findTableNameTem();
            if (allData != null && allData.size()>0){
            for (HashMap<String, String> map : tableNameTem) {
                if (map.get("table_name").equals("总账基础信息")){
                    List<HashMap<String, String>> table_name = allData.get(map.get("table_name"));
                    for (HashMap<String, String> stringStringHashMap : table_name) {
                        modeRule = stringStringHashMap.get("会计科目编号规则");
                    }
                }
                if (map.get("table_name").equals("电子账簿")){
                    List<HashMap<String, String>> table_name = allData.get(map.get("table_name"));
                    for (HashMap<String, String> stringStringHashMap : table_name) {
                        modeId = stringStringHashMap.get("电子账簿编号");
                        modeName = stringStringHashMap.get("电子账簿名称");
                        modeYear = stringStringHashMap.get("会计年度");
                    }
                }
            }
            }
            CompletableFuture.runAsync(() -> {

                for (HashMap<String, String> stringStringHashMap : tableNameTem) {
                    String tableName = stringStringHashMap.get("table_code");
                    String tableCName = stringStringHashMap.get("table_name");
                    List<NameField> filedNameTem = nameFieldService.findFiledNameTem(tableName);
                    List<HashMap<String, String>> objects1 = allData.get(tableCName);
                    String tableCC = "";
                    ArrayList<String> list = new ArrayList<>();
                    if (objects1 != null && objects1.size() >0) {
                        for (HashMap<String, String> jsonObject : objects1) {
                            List<String> values = new ArrayList<>();
                            List<String> columns = new ArrayList<>();
                            columns.add("acc_mode");
                            values.add(s1);
                            for (NameField nameField : filedNameTem) {
                                String value = (String) jsonObject.get(nameField.getName());
                                values.add(value);
                                columns.add(nameField.getField());
                            }
                            StringBuilder valueStringBuilder = new StringBuilder();
                            valueStringBuilder.append("(").append("'").append(UUID.randomUUID().toString()).append("',");
                            for (String value : values) {
                                if (value == null || value.equals("") ||value.equals("null")){
                                    valueStringBuilder.append("'").append("'").append(",");

                                }else {
                                    valueStringBuilder.append("'").append(value).append("'").append(",");

                                }
                            }
                            StringBuilder columnsStringBuilder = new StringBuilder();
                            columnsStringBuilder.append("(").append("id").append(",");
//                        columnsStringBuilder.append("(");
                            for (String column : columns) {
                                columnsStringBuilder.append(column).append(",");
                            }
                            columnsStringBuilder.deleteCharAt(columnsStringBuilder.length() - 1);
                            valueStringBuilder.deleteCharAt(valueStringBuilder.length() - 1);
                            valueStringBuilder.append(")");
                            columnsStringBuilder.append(")");
                            String tableValues = valueStringBuilder.toString();
                            String columnsValues = columnsStringBuilder.toString();
                            if (tableCC.equals("")){
                                tableCC = columnsValues;
                            }
                            list.add(tableValues);
                        }
                        String tableValues = "";
                        for (String s : list) {
                            tableValues = tableValues+","+s;
                        }
                        String substring = tableValues.substring(1);
                        nameFieldService.insertData(tableName, substring, tableCC);

                    }

                }
                // 执行批量插入操作
            });


            if (keys != null) {
                for (String key : keys) {
                    redisTemplate.delete(key);
                }
            }
            // 在这里实现将数据保存到数据库的逻辑
            HashMap<String, String> accMode = new HashMap<>();
            accMode.put("id",s1);
            accMode.put("acc_mode_code",modeId);
            accMode.put("acc_mode_name",modeName);
            accMode.put("acc_mode_year",modeYear);
            accMode.put("acc_mode_code_rule",modeRule);
            nameFieldService.saveAccMode(accMode);
            // ...
            System.out.println("数据保存成功");
            return success("数据保存成功");
        } catch (Exception e) {
            e.printStackTrace();
            return error();
        }
    }

    @PostMapping("/clearData")
    public AjaxResult clearData(){
        Long userId = SecurityUtils.getUserId();
        Set<String> keys = redisTemplate.keys(userId + ":*");
        if (keys != null) {
            for (String key : keys) {
                redisTemplate.delete(key);
            }
        }

        return success();
    }


            @PostMapping("/updateData")
    public AjaxResult updateData(
            @RequestParam String key,
            @RequestParam int index,
            @RequestBody Map<String, Object> data) {
        try {
            Long userId = SecurityUtils.getUserId();

            String redisKey = userId + ":" + key;
            // 获取当前列表
            List<Object> list = redisTemplate.opsForList().range(redisKey, 0, -1);

            // 更新指定位置的数据
            if (list != null) {
                list.set(index, data);
                redisTemplate.delete(redisKey);
                redisTemplate.opsForList().rightPushAll(redisKey, list);
            }

            return success("数据更新成功");
        } catch (Exception e) {
            e.printStackTrace();
            return error();
        }
    }

    private JSONObject convertToJSON(Element element) {
        JSONObject json = new JSONObject();
        NodeList nodeList = element.getChildNodes();

        for (int i = 0; i < nodeList.getLength(); i++) {
            Node node = nodeList.item(i);

            if (node.getNodeType() == Node.ELEMENT_NODE) {
                Element childElement = (Element) node;
                String nodeName = childElement.getNodeName();
                JSONObject childJson = convertToJSON(childElement);

                if (childJson.isEmpty()) {
                    String nodeValue = childElement.getTextContent().trim();
                    if (json.has(nodeName)) {
                        Object existing = json.get(nodeName);
                        JSONArray array;
                        if (existing instanceof JSONArray) {
                            array = (JSONArray) existing;
                        } else {
                            array = new JSONArray();
                            array.put(existing);
                        }
                        array.put(nodeValue);
                        json.put(nodeName, array);
                    } else {
                        json.put(nodeName, nodeValue);
                    }
                } else {
                    if (json.has(nodeName)) {
                        Object existing = json.get(nodeName);
                        JSONArray array;
                        if (existing instanceof JSONArray) {
                            array = (JSONArray) existing;
                        } else {
                            array = new JSONArray();
                            array.put(existing);
                        }
                        array.put(childJson);
                        json.put(nodeName, array);
                    } else {
                        json.put(nodeName, childJson);
                    }
                }
            }
        }

        return json;
    }

    private Map<String, Object> jsonToMap(JSONObject jsonObject) {
        Map<String, Object> map = new HashMap<>();
        for (String key : jsonObject.keySet()) {
            Object value = jsonObject.get(key);
            if (value instanceof JSONObject) {
                map.put(key, Collections.singletonList(jsonToMap((JSONObject) value)));
            } else if (value instanceof JSONArray) {
                map.put(key, jsonToList((JSONArray) value));
            } else {
                map.put(key, value);
            }
        }
        return map;
    }

    private Object jsonToList(JSONArray array) {
        List<Object> list = new ArrayList<>();
        for (int i = 0; i < array.length(); i++) {
            Object value = array.get(i);
            if (value instanceof JSONObject) {
                list.add(jsonToMap((JSONObject) value));
            } else if (value instanceof JSONArray) {
                list.add(jsonToList((JSONArray) value));
            } else {
                list.add(value);
            }
        }
        return list;
    }

}
